    def set_symmetry(self, mode):
        """ Sets the fractionalization matrix, orthogonalization matrix and symmetry matrices
            for a structure entity. The symmetry matrices can be either from the crystallographic
            tables.
        """
        # if something fails within this function it's likely to be a bogus PDB file.
        self.mode = mode
        if mode == 'raw':
            self.fmx, self.omx, self.mxs, self.cmx = self.get_symmetry(self.raw_header, mode)
        elif mode == 'bio':
            self.fmx, self.omx, self.mxs, self.cmx = self.get_symmetry(self.raw_header, mode)
        elif mode == 'table':
            self.fmx, self.omx, self.mxs, self.cmx = self.get_symmetry(self.header, mode)

    def set_crystal(self, n):
        self.n = 2
    def expand_symmetry(self):
        """ Expands the contents of the asymmetric unit as stored in a PDB file to the P1 space group.
            Requires a PDB file with correct CRYST1 field and space group information.
        """
        atoms = einput(self[(0,)], 'A')                        # there should be only one anyway
        coords = array(atoms._data_children('coords'))              # get coordinates
        all_coords = self.coords_to_symmetry(coords, self.fmx, self.omx, self.mxs, self.mode)      # expand to p1 coordinates
        for i in xrange(1,len(self.mxs)):                                # we update the structure
            new_model = deepcopy(self[(0,)])                   # with additional models which
            self.link()                          # *           # reflect the symmetry generated
            new_atoms = einput(new_model, 'A')                      # molecules
            new_coords = all_coords[i]                              # get the new matrix
            for (atom_id, new_coord) in izip(atoms.keys(),new_coords):
                new_atoms[atom_id].coords = new_coord               # feed atoms with new coordinates
            new_model.set_name(i)                                   # the models are numbered by the
            self.add_child(new_model)                          # symmetry operations with identity
        self.link()                                            # being the first model
        # * we need to link the structure after deepcopy because this function calls the _get_state method
        # which involves unlinking of the entity

    def expand_crystal(self):
        """ Expands the contents of the asymmetric unit as stored in a PDB file to a crystal
            of given size.
            Requires a PDB file with correct CRYST1 field and space group information.
        """
        tmp_model = deepcopy(self[(0,)])
        tmp_model.del_parent()                          # the parent is not needed will be added later
        tmp_model.link()
        atoms = einput(tmp_model, 'A')                  # there should be only one anyway
        coords = array(atoms._data_children('coords'))
        all_coords = self.coords_to_crystal(self.coords_to_symmetry\
                    (coords, self.fmx, self.omx, self.mxs, self.mode), self.fmx, self.omx, self.n)
        # we first expand the coordinates to the P1 space group and later apply primitive lattice
        # translations to generate a crystal of a given size.
        # -2,-1,0,1,2 (n = 2) // 2*2 + 1 = 5 // 5^3 all combinations
        for i in xrange(0, int(pow(2*self.n+1, 3))):
            for j in xrange(0, len(self.mxs)):
                new_model = deepcopy(tmp_model)         # see expand_to_p1
                tmp_model.link()
                new_atoms = einput(new_model, 'A')
                new_coords = all_coords[i,j]            # the matrix is 4D
                for (atom_id, new_coord) in izip(atoms.keys(),new_coords):
                    new_atoms[atom_id].coords = new_coord
                new_model.set_name(j*1000 + i)          # the maximum number of symmetry operations is 64
                self.add_child(new_model)               # one layer of unit cels should be enough, 27
        self.link()